package org.chen.service.impl;

import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.chen.domain.dto.LoginDTO;
import org.chen.domain.dto.RegisterDTO;
import org.chen.domain.entity.User;
import org.chen.mapper.UserMapper;
import org.chen.security.jwt.JwtUtils;
import org.chen.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class AuthServiceImpl implements AuthService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public String login(LoginDTO loginDTO) {
        User user = userMapper.selectOne(
                new LambdaQueryWrapper<User>()
                        .eq(User::getUsername, loginDTO.getUsername())
        );

        if (user == null || !passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new BadCredentialsException("用户名或密码错误");
        }

        String token = jwtUtils.generateToken(user.getUsername());

        // 存储到Redis
        redisTemplate.opsForValue().set(
                "token:" + token,
                user.getUsername(),
                jwtUtils.getExpiration(),
                TimeUnit.MILLISECONDS
        );

        return token;
    }

    @Override
    public void register(RegisterDTO registerDTO) {
        // 检查用户名是否已存在
        if (userMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, registerDTO.getUsername())) > 0) {
            throw new RuntimeException("用户名已存在");
        }

        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setEmail(registerDTO.getEmail());
        user.setStatus(1);

        userMapper.insert(user);
    }

    @Override
    public String refreshToken(String token) {
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }

        // 验证旧token
        if (!jwtUtils.validateToken(token)) {
            throw new RuntimeException("Invalid token");
        }

        // 从旧token中获取用户名
        String username = jwtUtils.getUsernameFromToken(token);
        if (username == null) {
            throw new RuntimeException("Invalid token");
        }

        // 检查Redis中是否存在
        String redisKey = "token:" + token;
        Object storedUsername = redisTemplate.opsForValue().get(redisKey);
        if (storedUsername == null || !username.equals(storedUsername.toString())) {
            throw new RuntimeException("Token expired");
        }

        // 生成新token
        String newToken = jwtUtils.generateToken(username);

        // 删除旧token
        redisTemplate.delete(redisKey);

        // 存储新token
        redisTemplate.opsForValue().set(
                "token:" + newToken,
                username,
                jwtUtils.getExpiration(),
                TimeUnit.MILLISECONDS
        );

        return newToken;
    }

    @Override
    public boolean validateToken(String token) {
        boolean b = jwtUtils.validateToken(token);
        if (b){
            String usernameFromToken = jwtUtils.getUsernameFromToken(token);
            return !StringUtils.isEmpty(usernameFromToken);
        }else {
            return false;
        }
    }

    @Override
    public void logout() {
        String token = getTokenFromRequest();
        if (token != null) {
            redisTemplate.delete("token:" + token);
        }
    }

    private String getTokenFromRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }


}
